
#include "IIC.h"
#include "OLED.h"
#include "oledfont.h"
#include "pic.h"
#include <string.h>

// 64*128 OLED screen
static byte screen_data[8][128] = {0};

// static int OLED_char_code(char s[], int size) {
//     int char_code = 0;
//     for (int i = 0; i < size; i++) {
//         char_code |= s[i] << 8 * (size - i - 1);
//     }
//     return char_code;
// }

// 找到字库中的索引
static c32 OLED_char_code_to_char_matrix_index(int char_code) {
    int total_size = sizeof(bus_font_mappings) / sizeof(int);
    c32 idx = 0;
    for (int i = 0; i < total_size / 2; i++) {
        if (bus_font_mappings[i][0] == char_code) {
            idx = bus_font_mappings[i][1];
            break;
        }
    }
    return idx;
}

// 单个字符（包括汉字）找到字库中的索引
// static int OLED_char_to_char_matrix_index(char s[], int size) {
//     return OLED_char_code_to_char_matrix_index(OLED_char_code(s, size));
// }

int OLED_str_to_str(c32 dest[], int d_len, char src[], int s_len) {
    // p();
    int len = 0;
    // p_str(src);
    // 每次清空dest，否则重复使用的话会有问题
    for (int i = 0; i < d_len; i++) {
        dest[i] = 0;
    }
    for (int i = 0; src[i]; i++) {
        if (src[i] & 0x80) {
            dest[len] <<= 8;
            dest[len] |= src[i];
            // 中文字符在ASCII码中占两字节
            if (dest[len] & 0x8000) {
                len++;
            }
        } else {
            dest[len] = src[i];
            len++;
        }
    }
    for (int i = 0; i < len; i++) {
        // printf("%#x", dest[i]);
        dest[i] = OLED_char_code_to_char_matrix_index(dest[i]);
        // printf(",%d\r\n", dest[i]);
    }
    // p();
    return len;
}

static void OLED_send_data(byte data[], int len) {
    byte d[128 * 2 + 1] = {0};

    // slave address
    byte address = 0x78;

    // control byte : D/C# = 1 => data
    byte data_ctrl = 0x40;

    d[0] = address;
    d[1] = data_ctrl;

    memcpy(d + 2, data, len);

    IIC_output_data(d, len + 2);
}

static void OLED_send_CMD(byte cmd[], int len) {
    byte c[101] = {0};

    // slave address
    byte address = 0x78;

    // control byte : D/C# = 0 => control
    byte cmd_ctrl = 0;

    c[0] = address;
    c[1] = cmd_ctrl;

    memcpy(c + 2, cmd, len);

    IIC_output_data(c, len + 2);
}

void OLED_show_screen() {

    byte cmd[8] = {0};

    // 64 rows 8 pages
    for (int i = 0; i < 8; i++) {
        // set start page
        cmd[0] = 0xB0 + i;
        // set start column 0
        cmd[1] = 0;
        cmd[2] = 0x10;
        OLED_send_CMD(cmd, 3);
        // 128 columns
        for (int j = 0; j < 128; j++) {
            OLED_send_data(&screen_data[i][j], 1);
        }
    }
}
void OLED_set_all_bytes(byte color) {
    // 64 rows 8 pages
    for (int i = 0; i < 8; i++) {
        // 128 columns
        for (int j = 0; j < 128; j++) {
            screen_data[i][j] = color;
        }
    }
    OLED_show_screen();
}
// 局部更新 字节级
static void OLED_draw_page_column_byte(int page, int col) {
    byte cmd[3] = {0};
    // set start page
    cmd[0] = 0xB0 + page;
    // set start column 0
    cmd[1] = 0xF & col;
    cmd[2] = 0x10 + (col >> 4);
    OLED_send_CMD(cmd, 3);
    OLED_send_data(&screen_data[page][col], 1);
}

// x max 64, y  max 128
void OLED_set_pixel(int x, int y, byte color) {

    int page = x / 8;
    int bit_pos = x % 8;
    if (color > 0) {
        screen_data[page][y] |= 1 << bit_pos;
    } else {
        screen_data[page][y] &= ~(1 << bit_pos);
    }

    OLED_draw_page_column_byte(page, y);
}

// char code 4 byte
void OLED_draw_text(int x, int y, c32 str[], int len) {

    int start_y = y;
    for (int i = 0; i < len; i++) {

        c32 char_code = str[i];

        if (char_code < 63) {

            // 8X16 English word
            int char_width = 8;

            char *half_up = bus_fonts[char_code];

            for (int j = 0; j < char_width; j++) {
                byte col_byte = half_up[j];
                for (int bit = 0; bit < 8; bit++) {
                    // 计算任意位置的颜色
                    byte color = col_byte >> bit & 1;
                    int row_idx = x + bit;
                    int col_idx = start_y + j;
                    OLED_set_pixel(row_idx, col_idx, color);
                }
            }
            char *half_down = half_up + 8;
            for (int j = 0; j < char_width; j++) {
                byte col_byte = half_down[j];
                for (int bit = 0; bit < 8; bit++) {
                    // 计算任意位置的颜色
                    byte color = col_byte >> bit & 1;
                    int row_idx = x + 8 + bit;
                    int col_idx = start_y + j;
                    OLED_set_pixel(row_idx, col_idx, color);
                }
            }
            start_y += char_width;
        } else {

            // 16X16 Chinese word
            int char_width = 16;
            // c32 char_code = str[i];
            char *half_up = bus_fonts[char_code];

            for (int j = 0; j < char_width; j++) {
                byte col_byte = half_up[j];
                for (int bit = 0; bit < 8; bit++) {
                    // 计算任意位置的颜色
                    byte color = col_byte >> bit & 1;
                    int row_idx = x + bit;
                    int col_idx = start_y + j;
                    OLED_set_pixel(row_idx, col_idx, color);
                }
            }
            char *half_down = bus_fonts[char_code + 1];
            for (int j = 0; j < char_width; j++) {
                byte col_byte = half_down[j];
                for (int bit = 0; bit < 8; bit++) {
                    // 计算任意位置的颜色
                    byte color = col_byte >> bit & 1;
                    int row_idx = x + 8 + bit;
                    int col_idx = start_y + j;
                    OLED_set_pixel(row_idx, col_idx, color);
                }
            }
            start_y += char_width;
        }
    }
}

void OLED_dark_screen() { OLED_set_all_bytes(0); }

void OLED_clear_screen() { OLED_dark_screen(); }

void OLED_text(int x, int y, char *s) {
    c32 d[100] = {0};
    int len = OLED_str_to_str(d, 100, s, 100);
    OLED_draw_text(0, 0, d, len);
}

void OLED_init() {

    // p();
    // open port
    IIC_init();

    byte cmd[8] = {0};

    // close display
    cmd[0] = 0xAE;
    OLED_send_CMD(cmd, 1);

    // Charge enable
    cmd[0] = 0x8D;
    cmd[1] = 0x94;
    OLED_send_CMD(cmd, 2);

    // open display
    cmd[0] = 0xAF;
    OLED_send_CMD(cmd, 1);
}

void OLED_clear() {

    byte col_color_byte = 0;
    byte cmd[8] = {0};
    // 8 pages
    for (int page = 0; page < 8; page++) {
        // set start page
        cmd[0] = 0xB0 + page;
        OLED_send_CMD(cmd, 1);

        // 128 colums per page
        for (int col = 0; col < 128; col++) {
            // set start column
            cmd[0] = col & 0xF;
            cmd[1] = 0x10 + (col >> 4);
            OLED_send_CMD(cmd, 2);
            // set color this column
            OLED_send_data(&col_color_byte, 1);
        }
    }
}

void OLED_white_screen() {

    byte col_color_byte = 0xFF;
    byte cmd[8] = {0};
    // 8 pages
    for (int page = 0; page < 8; page++) {
        // set start page
        cmd[0] = 0xB0 + page;
        OLED_send_CMD(cmd, 1);

        // 128 colums per page
        for (int col = 0; col < 128; col++) {
            // set start column
            cmd[0] = col & 0xF;
            cmd[1] = 0x10 + (col >> 4);
            OLED_send_CMD(cmd, 2);
            // set color this column
            OLED_send_data(&col_color_byte, 1);
        }
    }
}

// void OLED_draw_string(int start_page, int start_column, char str[], int len)
// {

//     byte col_color_byte = 0;
//     int char_width = 6;
//     int delta = 32;
//     byte cmd[8] = {0};
//     // set start page
//     cmd[0] = 0xB0 + start_page;
//     OLED_send_CMD(cmd, 1);

//     // set start column
//     cmd[0] = start_column & 0xF;
//     cmd[1] = 0x10 + (start_column >> 4);
//     OLED_send_CMD(cmd, 2);

//     // column 128 bit
//     // rows 8 bit per page
//     // pages 8
//     // display 64*128
//     for (int char_index = 0; char_index < len; char_index++) {
//         char c = str[char_index];

//         for (int i = 0; i < char_width; i++) {
//             // 每次数据写入后，GDDRAM列地址指针将自动增加一个。
//             // 不用每次设置起始列
//             col_color_byte = F6x8[c - delta][i];
//             OLED_send_data(&col_color_byte, 1);
//         }
//     }
// }

// void OLED_draw_hanzi(int x, int y, int str[] /*存储是汉字编码*/, int len) {
//     byte col_color_byte = 0;
//     int char_width = 16;
//     byte cmd[8] = {0};

//     int row_idx = x * 2;
//     for (int i = 0; i < len; i++) {
//         // adjust col position
//         int col_idx = y + i * char_width;
//         // 上半部
//         // set start page
//         // rows
//         cmd[0] = 0xB0 + row_idx;
//         // set start column
//         // colums
//         cmd[1] = col_idx & 0xF;
//         cmd[2] = 0x10 + (col_idx >> 4);
//         OLED_send_CMD(cmd, 3);
//         int shape_code_idx = str[i] * 2;
//         // 每次数据写入后 , 列地址指针自动 +1
//         for (int j = 0; j < char_width; j++) {
//             col_color_byte = Hzk[shape_code_idx][j];
//             OLED_send_data(&col_color_byte, 1);
//         }

//         // 下半部
//         //  set start page
//         // rows
//         cmd[0] = 0xB0 + row_idx + 1;
//         // set start column
//         // colums
//         cmd[1] = col_idx & 0xF;
//         cmd[2] = 0x10 + (col_idx >> 4);
//         OLED_send_CMD(cmd, 3);

//         // 每次数据写入后 , 列地址指针自动 +1
//         for (int j = 0; j < char_width; j++) {
//             col_color_byte = Hzk[shape_code_idx + 1][j];
//             OLED_send_data(&col_color_byte, 1);
//         }
//     }
// }

void OLED_draw_tiger() {

    byte cmd[8] = {0};
    byte *tiger_data = &tiger[0][0];
    // 8 pages
    for (int page = 0; page < 8; page++) {
        // set start page
        cmd[0] = 0xB0 + page;
        // set start column 0
        cmd[1] = 0;
        cmd[2] = 0x10;
        OLED_send_CMD(cmd, 3);

        // 128 colums per page
        for (int col = 0; col < 128; col++) {
            // set color this column
            OLED_send_data(&tiger_data[page * 128 + col], 1);
        }
    }
}
